package com.touchealth.test.meinian;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

/**
 * Created by liquan on 2017/11/29.
 */
public class AESUtil {
    private static final String KEY_AES = "AES";
    private static final String KEY = "15360b73384a48f5";

    private static final String CHARSET_UTF_8 = "utf-8";
    private static final String AES = "AES";



    private AESUtil(){}

    /**
     *
     * @param src
     * @return
     * @throws Exception
     */
    public static String encrypt(String src) throws Exception {
        byte[] raw = KEY.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_AES);
        Cipher cipher = Cipher.getInstance(KEY_AES);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(src.getBytes());
        return byte2hex(encrypted);
    }

    public static String decrypt(String src) throws Exception {
        byte[] raw = KEY.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_AES);
        Cipher cipher = Cipher.getInstance(KEY_AES);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] encrypted1 = hex2byte(src);
        byte[] original = cipher.doFinal(encrypted1);
        return new String(original);
    }


    /**
     * @param key
     *            密钥
     * @param src
     *            明文字符串
     * @return 密文字节数组
     */
    public static String encrypt(String src,String key) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(key.getBytes()), AES);
        Cipher cipher = Cipher.getInstance(AES);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encypted = cipher.doFinal(src.getBytes());
        return  byte2hex(encypted);
    }

    /**
     * AES加密，加密模式：AES/CBC/NoPadding
     * @param src 待加密的字符串
     * @param key16Length 密码、偏移量，长度：16位
     * @return
     */
    public static byte[] encryptForCBC(String src, String key16Length) {
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("AES/CBC/NoPadding"); // 算法/模式/补码方式
            int blockSize = cipher.getBlockSize();
            byte[] dataBytes = src.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keyspec = new SecretKeySpec(key16Length.getBytes(), AES);
            IvParameterSpec ivspec = new IvParameterSpec(key16Length.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            return cipher.doFinal(plaintext);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param src
     *            密文
     * @param key
     *            密钥
     * @return 解密后的字符串
     */
    public static String decrypt(String src, String key) throws Exception {
        byte[] encrypted = hex2byte(src);
        SecretKeySpec secretKeySpec = new SecretKeySpec(getRawKey(key.getBytes()), AES);
        Cipher cipher = Cipher.getInstance(AES);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted);
    }

    /**
     * @param seed 种子数据
     * @return 密钥数据
     */
    private static byte[] getRawKey(byte[] seed) throws Exception {
        byte[] rawKey = null;
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(seed);
        // AES加密数据块分组长度必须为128比特，密钥长度可以是128比特、192比特、256比特中的任意一个
        kgen.init(128, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        rawKey = secretKey.getEncoded();
        return rawKey;
    }

    public static String base64Encode(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }


    public static byte[] base64Decode(String base64Code) throws Exception {
        return new BASE64Decoder().decodeBuffer(base64Code);
    }

    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(KEY_AES);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), AES));


        return cipher.doFinal(content.getBytes(CHARSET_UTF_8));
    }

    /**
     * 与前端统一的aes加密算法
     * @param content
     * @param encryptKey
     * @return
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    }

    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        kgen.init(128);


        Cipher cipher = Cipher.getInstance(KEY_AES);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), AES));
        byte[] decryptBytes = cipher.doFinal(encryptBytes);


        return new String(decryptBytes);
    }

    /**
     * 与前端统一的aes解密算法
     * @param encryptStr
     * @param decryptKey
     * @return
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    }

    private static byte[] hex2byte(String strhex) {
        if (strhex == null) {
            return null;
        }
        int l = strhex.length();
        if (l % 2 == 1) {
            return null;
        }
        byte[] b = new byte[l / 2];
        for (int i = 0; i != l / 2; i++) {
            b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2),
                    16);
        }
        return b;
    }

    private static String byte2hex(byte[] b) {
        StringBuilder builder = new StringBuilder();
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                builder.append("0");
            }
            builder.append(stmp);

        }
        return builder.toString().toUpperCase();
    }

    /**
     * 响应参数加密算法
     * @throws Exception
     */
    public static String encryptToStr(String src, String appSecret) throws Exception {
        // 算法/模式/补码方式
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        int blockSize = cipher.getBlockSize();
        byte[] dataBytes = src.getBytes();
        int plaintextLength = dataBytes.length;
        if (plaintextLength % blockSize != 0) {
            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
        }
        byte[] plaintext = new byte[plaintextLength];
        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
        SecretKeySpec keyspec = new SecretKeySpec(appSecret.getBytes(), AES);
        IvParameterSpec ivspec = new IvParameterSpec(appSecret.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
        byte[] bytes = cipher.doFinal(plaintext);
        return Hex.encodeHexString(bytes);
    }

    /*** 响应参数解密算法 */
    public static String decryptForCBC(String src, String appSecret) throws Exception {
        // 算法/模式/补码方式
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        int blockSize = cipher.getBlockSize();
        byte[] dataBytes = Hex.decodeHex(src.toCharArray());
        int plaintextLength = dataBytes.length;
        if (plaintextLength % blockSize != 0) {
            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
        }
        byte[] plaintext = new byte[plaintextLength];
        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
        SecretKeySpec keyspec = new SecretKeySpec(appSecret.getBytes(), AES);
        IvParameterSpec ivspec = new IvParameterSpec(appSecret.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
        byte[] bytes = cipher.doFinal(plaintext);
        return new String(bytes, CHARSET_UTF_8);
    }

    /*** 响应参数解密算法 */
    public static String encodeToECBPk5Paddingi(String src, String appSecret) throws Exception {
        // 算法/模式/补码方式
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        byte[] dataBytes = src.getBytes("utf-8");
        SecretKeySpec keyspec = new SecretKeySpec(appSecret.getBytes("utf-8"), AES);
        cipher.init(Cipher.ENCRYPT_MODE, keyspec);
        byte[] bytes = cipher.doFinal(dataBytes);
        return new Base64().encodeToString(bytes);
    }

    public static void main(String[] args) throws Exception {
        String data = "PO17V5fdRVqFMbtTDwX9ATbmosv1KZa1Rpe1k0TzoE3if9gkkXPvGbLlZKulfvaZFrpPtKzg74RCnCjHD6ggymxqI7CmjYAMJXKdwM/VwBTwuTacovSQI7NwJhX3T7p4naCjgGHY3QmwrhOZDFWYaJULiopvplzOb0VuX+ez3884hKaxUchL+xxTBmn/BUl9oYkWixoCo/NSff8u+d5FaUgzbigjRvkxqfdg5Lb9TxHJmzlEePueKNmryJwrAN5F33lvRDdQDeDnQW5+OmjkMTUWUAUfBzGwCSaxOCxTvmvL3uuA2wAe6puYcTejtSrkOH2Bf3kA5EFSNdg1UvWf4f4w0R4cap8ylS2oqeMUhFCEQfa6OJZGYS5wHPZLcjZbm81DDSJkfZ4czhNRP5yJhELfmTM1YTrko8y7RtTb4Pbj+iCWqYriUuz4RA1Qp5PEHLole2pq4pFNdRGQVNt6MwgaaYmxri8JdsahdvX8kckcRTNdoBBbnrEYcjuQUHYUuIkmO8tSfT/m9nNKTHnlfJQ9GY9PqmfHNaHSjsnt2D/dPr31S+ZaLSmJAF5zkwYXk3tYAisPQBWoNOJMZ4FsVJapaNCHmbsMcC6DhDZ9hA8WDJtuc6pbVnrNgrcsAGrkyB1dGlEnAOjePQ/HSQB2Suag1ccLr7Iq2JXpRg7GIPzjMZ6G2bP/eHkGYBZQT9N0fstmWlHHEZ9Z3CN3n9si/ITIzM+mwNlf89Or0P/hR3OpG7p4aJZNARS7XjjA8W/k0gzMIsU0AMIQP3FK+bANj+BT117sdIYV/waCbUnoXAG3FxTHdTNhDD3TmRIk9PMXjhqjrLzo/jXrbqlBg7dNFLsSrXVigaRfUyYgitZslXJFpCxw4QlIvW3eo5qtnbEqgGeGF0z1a2EDFQx50kd6Yiuj3DMZfja4sfdILiD0ys2pWTFTydtvv5vYcss7uCHH2/is50dpNAmKI7YB7YIC42K13oIA48Hqqsq4102360831MHtDcPDbiGrFz5RIrboptwCtxMki3tPOb93jy2vFxfMoLDrbu6OEbdgXHEVpvc0Sjhb0j1C5UAy4IxtTkpXHGnXk253UyiZ63qZ6PMDo0435XoiY5FDqeKFOsMroaYfYXoSrDamz9zF/qACjhFJwU8pvOJA/shjJ8+qMwzjfHgScO8v9vv+b2umpEQIUYqQNVSVZBYecMMY+rbU+Kr4sF2dOqgJgPTONIfbf3IXOgn+c4sXn1X/xa8msq/0VYPFKrhEPRyS/K1ETZtKzPN5ZNpiQ9Yw/jvUb2iOgtdEFXi9tjDM3bVCoumzZMQlKViNm2TOD64T+LqYsTkatxPn";
        String decrypt = aesDecrypt(data, "abcdefgabcdefg12");
        System.out.println(decrypt);
    }


}
